package Salesman;

import Salesman.Data.DataProvider;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

public class TSPBound extends TSPEngine {

    private Queue queue;
    private Distances start;
    private Distances step;

    private boolean nextStep(Distances c) {

        if (c.getUnused().isEmpty()) {
            return false;
        }
        for (Integer i : c.getUnused()) {
            queue.offer(c.visit(i.intValue()));
        }
        step = queue.poll();
        if (step != null) {
            fireListener(new Step(step, queue.size()));
            incCounter();
            return true;
        }

        return false;
    }

    private boolean nextStep() {
        if (step != null) {
            return nextStep(step);
        }
        return false;
    }

    @Override
    public void start(City city) {
        queue = new Queue();
        this.start = DataProvider.getDistances().copy();
        List<Integer> unused = new LinkedList<Integer>();

        for (City c : DataProvider.getInSimulationCities()) {
            unused.add(DataProvider.getCityData().indexOf(c));
        }

        this.start.setUnused(unused);


        resetCounter();
        step = start.visit(DataProvider.getCityData().indexOf(city));
    }

    @Override
    public boolean next() {
        return nextStep();
    }

    private class Step extends AbstractStep {

        private Distances dist;
        private int queueSize;

        public Step(Distances dist, int queueSize) {
            this.dist = dist;
            this.queueSize = queueSize;
        }

        @Override
        public List<City> getCities() {
            List<City> result = new ArrayList<City>();
            for (int i : dist.getRoute()) {
                result.add(DataProvider.getCityData().get(i));
            }

            if (dist.getUnused().isEmpty()) {
                result.add(result.get(0));
            }

            return result;
        }

        @Override
        public String toString() {
            return "Route: " + dist.routeToString() + "\n"
                    + "noch offen: " + dist.unusedToString() + "\n"
                    + "min. Restweg: " + Double.toString(dist.minRemaining()) + " km\n"
                    + "Queue length: " + queueSize + "\n";
        }
    }
}
